using System;

namespace RTMP.SimpleClient.Helpers
{
    /// <summary>
    /// 提供小端字节序与基本数据类型之间的转换方法
    /// </summary>
    public static class SpanLittleEndianConverter
    {
        /// <summary>
        /// 将小端字节数组转换为 16 位有符号整数
        /// </summary>
        /// <param name="bytes">字节数组（长度必须正好是 2 个字节）</param>
        /// <returns>转换后的 short 值</returns>
        /// <exception cref="ArgumentException">当 bytes 长度不正确时抛出</exception>
        public static short LittleEndianToInt16(this Span<byte> bytes)
        {
            if (bytes.Length != 2)
                throw new ArgumentException("字节数组长度必须正好是 2 个字节", nameof(bytes));

            return (short)((bytes[1] << 8) | bytes[0]);
        }

        /// <summary>
        /// 将小端字节数组转换为 32 位有符号整数
        /// </summary>
        /// <param name="bytes">字节数组（长度必须正好是 4 个字节）</param>
        /// <returns>转换后的 int 值</returns>
        /// <exception cref="ArgumentException">当 bytes 长度不正确时抛出</exception>
        public static int LittleEndianToInt32(this Span<byte> bytes)
        {
            if (bytes.Length != 4)
                throw new ArgumentException("字节数组长度必须正好是 4 个字节", nameof(bytes));

            return (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
        }

        /// <summary>
        /// 将小端字节数组转换为 64 位有符号整数
        /// </summary>
        /// <param name="bytes">字节数组（长度必须正好是 8 个字节）</param>
        /// <returns>转换后的 long 值</returns>
        /// <exception cref="ArgumentException">当 bytes 长度不正确时抛出</exception>
        public static long LittleEndianToInt64(this Span<byte> bytes)
        {
            if (bytes.Length != 8)
                throw new ArgumentException("字节数组长度必须正好是 8 个字节", nameof(bytes));

            return ((long)bytes[7] << 56) | ((long)bytes[6] << 48) | ((long)bytes[5] << 40) | ((long)bytes[4] << 32) |
                   ((long)bytes[3] << 24) | ((long)bytes[2] << 16) | ((long)bytes[1] << 8) | bytes[0];
        }

        /// <summary>
        /// 将小端字节数组转换为双精度浮点数
        /// </summary>
        /// <param name="bytes">字节数组（长度必须正好是 8 个字节）</param>
        /// <returns>转换后的 double 值</returns>
        /// <exception cref="ArgumentException">当 bytes 长度不正确时抛出</exception>
        public static double LittleEndianToDouble(this Span<byte> bytes)
        {
            if (bytes.Length != 8)
                throw new ArgumentException("字节数组长度必须正好是 8 个字节", nameof(bytes));

            return BitConverter.ToDouble(bytes.ToArray(), 0);
        }

        /// <summary>
        /// 将小端字节数组转换为 16 位无符号整数
        /// </summary>
        /// <param name="bytes">字节数组（长度必须正好是 2 个字节）</param>
        /// <returns>转换后的 ushort 值</returns>
        /// <exception cref="ArgumentException">当 bytes 长度不正确时抛出</exception>
        public static ushort LittleEndianToUInt16(this Span<byte> bytes)
        {
            if (bytes.Length != 2)
                throw new ArgumentException("字节数组长度必须正好是 2 个字节", nameof(bytes));

            return (ushort)((bytes[1] << 8) | bytes[0]);
        }

        /// <summary>
        /// 将小端字节数组转换为 32 位无符号整数
        /// </summary>
        /// <param name="bytes">字节数组（长度必须正好是 4 个字节）</param>
        /// <returns>转换后的 uint 值</returns>
        /// <exception cref="ArgumentException">当 bytes 长度不正确时抛出</exception>
        public static uint LittleEndianToUInt32(this Span<byte> bytes)
        {
            if (bytes.Length != 4)
                throw new ArgumentException("字节数组长度必须正好是 4 个字节", nameof(bytes));

            return (uint)((bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0]);
        }

        /// <summary>
        /// 将小端字节数组转换为 64 位无符号整数
        /// </summary>
        /// <param name="bytes">字节数组（长度必须正好是 8 个字节）</param>
        /// <returns>转换后的 ulong 值</returns>
        /// <exception cref="ArgumentException">当 bytes 长度不正确时抛出</exception>
        public static ulong LittleEndianToUInt64(this Span<byte> bytes)
        {
            if (bytes.Length != 8)
                throw new ArgumentException("字节数组长度必须正好是 8 个字节", nameof(bytes));

            return ((ulong)bytes[7] << 56) | ((ulong)bytes[6] << 48) | ((ulong)bytes[5] << 40) | ((ulong)bytes[4] << 32) |
                   ((ulong)bytes[3] << 24) | ((ulong)bytes[2] << 16) | ((ulong)bytes[1] << 8) | bytes[0];
        }

        /// <summary>
        /// 将 16 位有符号整数转换为小端字节数组
        /// </summary>
        /// <param name="value">要转换的 short 值</param>
        /// <param name="buffer">输出缓冲区（长度必须至少为 2）</param>
        /// <returns>实际写入的字节数</returns>
        public static int GetLittleEndianSpan(this short value, Span<byte> buffer)
        {
            if (buffer.Length < 2)
                throw new ArgumentException("缓冲区长度至少需要 2 个字节", nameof(buffer));

            buffer[0] = (byte)value;
            buffer[1] = (byte)(value >> 8);
            return 2;
        }

        /// <summary>
        /// 将 32 位有符号整数转换为小端字节数组
        /// </summary>
        /// <param name="value">要转换的 int 值</param>
        /// <param name="buffer">输出缓冲区（长度必须至少为 4）</param>
        /// <returns>实际写入的字节数</returns>
        public static int GetLittleEndianSpan(this int value, Span<byte> buffer)
        {
            if (buffer.Length < 4)
                throw new ArgumentException("缓冲区长度至少需要 4 个字节", nameof(buffer));

            buffer[0] = (byte)value;
            buffer[1] = (byte)(value >> 8);
            buffer[2] = (byte)(value >> 16);
            buffer[3] = (byte)(value >> 24);
            return 4;
        }

        /// <summary>
        /// 将 64 位有符号整数转换为小端字节数组
        /// </summary>
        /// <param name="value">要转换的 long 值</param>
        /// <param name="buffer">输出缓冲区（长度必须至少为 8）</param>
        /// <returns>实际写入的字节数</returns>
        public static int GetLittleEndianSpan(this long value, Span<byte> buffer)
        {
            if (buffer.Length < 8)
                throw new ArgumentException("缓冲区长度至少需要 8 个字节", nameof(buffer));

            buffer[0] = (byte)value;
            buffer[1] = (byte)(value >> 8);
            buffer[2] = (byte)(value >> 16);
            buffer[3] = (byte)(value >> 24);
            buffer[4] = (byte)(value >> 32);
            buffer[5] = (byte)(value >> 40);
            buffer[6] = (byte)(value >> 48);
            buffer[7] = (byte)(value >> 56);
            return 8;
        }

        /// <summary>
        /// 将 16 位无符号整数转换为小端字节数组
        /// </summary>
        /// <param name="value">要转换的 ushort 值</param>
        /// <param name="buffer">输出缓冲区（长度必须至少为 2）</param>
        /// <returns>实际写入的字节数</returns>
        public static int GetLittleEndianSpan(this ushort value, Span<byte> buffer)
        {
            if (buffer.Length < 2)
                throw new ArgumentException("缓冲区长度至少需要 2 个字节", nameof(buffer));

            buffer[0] = (byte)value;
            buffer[1] = (byte)(value >> 8);
            return 2;
        }

        /// <summary>
        /// 将 32 位无符号整数转换为小端字节数组
        /// </summary>
        /// <param name="value">要转换的 uint 值</param>
        /// <param name="buffer">输出缓冲区（长度必须至少为 4）</param>
        /// <returns>实际写入的字节数</returns>
        public static int GetLittleEndianSpan(this uint value, Span<byte> buffer)
        {
            if (buffer.Length < 4)
                throw new ArgumentException("缓冲区长度至少需要 4 个字节", nameof(buffer));

            buffer[0] = (byte)value;
            buffer[1] = (byte)(value >> 8);
            buffer[2] = (byte)(value >> 16);
            buffer[3] = (byte)(value >> 24);
            return 4;
        }

        /// <summary>
        /// 将 64 位无符号整数转换为小端字节数组
        /// </summary>
        /// <param name="value">要转换的 ulong 值</param>
        /// <param name="buffer">输出缓冲区（长度必须至少为 8）</param>
        /// <returns>实际写入的字节数</returns>
        public static int GetLittleEndianSpan(this ulong value, Span<byte> buffer)
        {
            if (buffer.Length < 8)
                throw new ArgumentException("缓冲区长度至少需要 8 个字节", nameof(buffer));

            buffer[0] = (byte)value;
            buffer[1] = (byte)(value >> 8);
            buffer[2] = (byte)(value >> 16);
            buffer[3] = (byte)(value >> 24);
            buffer[4] = (byte)(value >> 32);
            buffer[5] = (byte)(value >> 40);
            buffer[6] = (byte)(value >> 48);
            buffer[7] = (byte)(value >> 56);
            return 8;
        }

        /// <summary>
        /// 将双精度浮点数转换为小端字节数组
        /// </summary>
        /// <param name="value">要转换的 double 值</param>
        /// <param name="buffer">输出缓冲区（长度必须至少为 8）</param>
        /// <returns>实际写入的字节数</returns>
        public static int GetLittleEndianSpan(this double value, Span<byte> buffer)
        {
            if (buffer.Length < 8)
                throw new ArgumentException("缓冲区长度至少需要 8 个字节", nameof(buffer));

            // 获取小端字节数组
            byte[] littleEndianBytes = BitConverter.GetBytes(value);

            // 复制到缓冲区
            littleEndianBytes.CopyTo(buffer);
            return 8;
        }

        /// <summary>
        /// 获取值对应的小端字节数组（分配新数组）
        /// </summary>
        public static byte[] GetLittleEndianBytes(this short value)
        {
            var b = new byte[2];
            value.GetLittleEndianSpan(b.AsSpan());
            return b;
        }

        /// <summary>
        /// 获取值对应的小端字节数组（分配新数组）
        /// </summary>
        public static byte[] GetLittleEndianBytes(this int value)
        {
            var b = new byte[4];
            value.GetLittleEndianSpan(b.AsSpan());
            return b;
        }

        /// <summary>
        /// 获取值对应的小端字节数组（分配新数组）
        /// </summary>
        public static byte[] GetLittleEndianBytes(this long value)
        {
            var b = new byte[8];
            value.GetLittleEndianSpan(b.AsSpan());
            return b;
        }

        /// <summary>
        /// 获取值对应的小端字节数组（分配新数组）
        /// </summary>
        public static byte[] GetLittleEndianBytes(this ushort value)
        {
            var b = new byte[2];
            value.GetLittleEndianSpan(b.AsSpan());
            return b;
        }

        /// <summary>
        /// 获取值对应的小端字节数组（分配新数组）
        /// </summary>
        public static byte[] GetLittleEndianBytes(this uint value)
        {
            var b = new byte[4];
            value.GetLittleEndianSpan(b.AsSpan());
            return b;
        }

        /// <summary>
        /// 获取值对应的小端字节数组（分配新数组）
        /// </summary>
        public static byte[] GetLittleEndianBytes(this ulong value)
        {
            var b = new byte[8];
            value.GetLittleEndianSpan(b.AsSpan());
            return b;
        }

        /// <summary>
        /// 获取值对应的小端字节数组（分配新数组）
        /// </summary>
        public static byte[] GetLittleEndianBytes(this double value)
        {
            var b = new byte[8];
            value.GetLittleEndianSpan(b.AsSpan());
            return b;
        }
    }
}
